require("lfs");
local cjson = require("cjson");
string.split = function(s, p)
    local rt= {};
    string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end );
    return rt;
end
function string.trim(input)
    input = string.gsub(input, "^[ \t\n\r]+", "")
    return string.gsub(input, "[ \t\n\r]+$", "")
end
function dump(value, desciption, nesting)
    if type(nesting) ~= "number" then nesting = 3 end

    local lookupTable = {}
    local result = {}

    local function _v(v)
        if type(v) == "string" then
            v = "\"" .. v .. "\""
        end
        return tostring(v)
    end

    local traceback = string.split(debug.traceback("", 2), "\n")
    print("dump from: " .. string.trim(traceback[3]))

    local function _dump(value, desciption, indent, nest, keylen)
        desciption = desciption or "<var>"
        local spc = ""
        if type(keylen) == "number" then
            spc = string.rep(" ", keylen - string.len(_v(desciption)))
        end
        if type(value) ~= "table" then
            result[#result +1 ] = string.format("%s%s%s = %s", indent, _v(desciption), spc, _v(value))
        elseif lookupTable[value] then
            result[#result +1 ] = string.format("%s%s%s = *REF*", indent, desciption, spc)
        else
            lookupTable[value] = true
            if nest > nesting then
                result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, desciption)
            else
                result[#result +1 ] = string.format("%s%s = {", indent, _v(desciption))
                local indent2 = indent.."    "
                local keys = {}
                local keylen = 0
                local values = {}
                for k, v in pairs(value) do
                    keys[#keys + 1] = k
                    local vk = _v(k)
                    local vkl = string.len(vk)
                    if vkl > keylen then keylen = vkl end
                    values[k] = v
                end
                table.sort(keys, function(a, b)
                    if type(a) == "number" and type(b) == "number" then
                        return a < b
                    else
                        return tostring(a) < tostring(b)
                    end
                end)
                for i, k in ipairs(keys) do
                    _dump(values[k], k, indent2, nest + 1, keylen)
                end
                result[#result +1] = string.format("%s}", indent)
            end
        end
    end
    _dump(value, desciption, "- ", 1)

    for i, line in ipairs(result) do
        print(line)
    end
end

function class(classname, super)
    local superType = type(super)
    local cls
    if superType ~= "function" and superType ~= "table" then
        superType = nil
        super = nil
    end
    if superType == "function" or (super and super.__ctype == 1) then
        cls = {}
        if superType == "table" then
            for k,v in pairs(super) do cls[k] = v end
            cls.__create = super.__create
            cls.super    = super
        else
            cls.__create = super
            cls.ctor = function() end
        end
        cls.__cname = classname
        cls.__ctype = 1
        function cls.new(...)
            local instance = cls.__create(...)
            for k,v in pairs(cls) do instance[k] = v end
            instance.class = cls
            instance:ctor(...)
            return instance
        end
    else
        if super then
            cls = {}
            setmetatable(cls, {__index = super})
            cls.super = super
        else
            cls = {ctor = function() end}
        end
        cls.__cname = classname
        cls.__ctype = 2
        cls.__index = cls
        function cls.new(...)
            local instance = setmetatable({}, cls)
            instance.class = cls
            instance:ctor(...)
            return instance
        end
    end
    return cls
end

function handler(obj, method)
    return function(...)
        return method(obj, ...)
    end
end



local UpdateScene = class("UpdateScene", function()
    local scene = cc.Scene:create();
    return scene;
end)

function UpdateScene:ctor()
    --local projectDir = "../../../";
    --cc.FileUtils:getInstance():addSearchPath(projectDir .. "pkg/");
    --dump(cc.FileUtils:getInstance():getSearchPaths());
	--cc.FileUtils:getInstance():addSearchPath(projectDir .. "res/");
    --cc.FileUtils:getInstance():addSearchPath(projectDir .. "code/");
    local writePath = cc.FileUtils:getInstance():getWritablePath();
    local target = cc.Application:getInstance():getTargetPlatform()
    if target == 0 then
        writePath = string.gsub(writePath, '\\', '/');
    end
    local UPD_FOLDER = writePath .. "upd/";
    self.updFolder = UPD_FOLDER;
    self:make_dir(UPD_FOLDER);
    local paths = cc.FileUtils:getInstance():getSearchPaths();
    table.insert(paths,1,UPD_FOLDER);
    table.insert(paths,2,UPD_FOLDER .. "res/");
    table.insert(paths,3,UPD_FOLDER .. "src/");
    cc.FileUtils:getInstance():setSearchPaths(paths);
    local visibleRect = cc.Director:getInstance():getOpenGLView():getVisibleRect();
    local bg = cc.Sprite:create("png/launch_bg.png");
    bg:setPosition({x = visibleRect.x + visibleRect.width/2,y = visibleRect.y + visibleRect.height/2});
    self:addChild(bg);

    local node = cc.Node:create();
    node:setPosition({x = visibleRect.x + visibleRect.width/2,y = visibleRect.y + 100})
    self:addChild(node);

    local timerBg = cc.Sprite:create("png/loading_line_border.png");
    node:addChild(timerBg);
    local timer = cc.ProgressTimer:create(cc.Sprite:create("png/loading_line.png"));
    timer:setPercentage(0);
    timer:setBarChangeRate({x = 1,y = 0});
    timer:setType(1);
    timer:setMidpoint({x = 0,y = 0.5});
    node:addChild(timer);
    self.progressTimer = timer;
    local text = cc.Label:createWithSystemFont("", "fonts/msyh.ttf", 32);
    node:addChild(text);
    text:setPosition({x = 0,y = -50});
    self.text = text;
    self:post({cbk = handler(self,self.firstStepCbk),url = "http://www.macg.cn:8080/debug",params = {{key = "name",value = "zq"},{key = "fr",value = 1}}});
end


function UpdateScene:firstStepCbk(resp)
    dump(resp,"firstStepCbk",10);
    --test
    self:notNeedUpdate();
    --[[
    resp = resp.d;
    self.apUrl = resp.url;
    self.idkey = resp.idkey;
    self.ps = resp.ps;
    local curVersion = self:getCurVersion();
    local sys = self:getSys();
    local m = {ver = curVersion,sys = sys,mid = 36};
    m = cjson.encode(m);
    self:post({cbk = handler(self,self.secondStepCbk),url = self.apUrl,params = {{key = "id",value = "0"},{key = "v",value = "json"},{key = "m",value = m}}});
    --]]
end

function UpdateScene:secondStepCbk(resp)
    dump(resp,"secondStepCbk",10);
    local data = resp[1];
    if data.s == 0 then
        local d = data.d;
        local res = d.res;
        local serverVersion = res.ver;
        local curVersion = self:getCurVersion();
        self.vir = d.vir;
        if serverVersion ~= curVersion then
            self.text:setString("更新中,请稍后");
            self:updateRes(res);
        else
            local m = {ps = self.ps,id = 1,mid = 35};
            m = cjson.encode(m);
            self:post({cbk = handler(self,self.thirdStepCbk),url = self.apUrl,params = {{key = "id",value = "0"},{key = "v",value = "json"},{key = "m",value = m}}});
        end
    else
        self.text:setString("服务器出错");
    end
end



function UpdateScene:thirdStepCbk(resp)
    dump(resp,"thirdStepCbk",10);
    if resp[1].s == 0 then
        self.ps = resp[1].d.ps;
        self:notNeedUpdate();
    else
        --test
        self:notNeedUpdate();
    end
end


function UpdateScene:bigVersionUpdate()
    self:clean_dir(self.updFolder);
end
function UpdateScene:diffTable(oldTable,newTable)
    local reTable = {};
    for key, newFile in pairs(newTable) do
		local oldFile = oldTable[key];
        if oldFile then
			if newFile.crc == oldFile.crc and newFile.size == oldFile.size then
				--same file
			else
				reTable[key] = newFile;
			end
		else
			--new file
			reTable[key] = newFile;
		end
    end
    return reTable;
end



function UpdateScene:write_content_to_file(path,content,mode)
    mode = mode or "w+b"
    local file = io.open(path, mode)
    if file then
        local hr,err = file:write(content)
        if hr == nil then
            print(err)
            return false
        end
        io.close(file)
        return true
    else
        print("can't open file:"..path)
        return false
    end
end

function UpdateScene:is_file_exists(path)
    return cc.FileUtils:getInstance():isFileExist(path)
end

function UpdateScene:clean_dir(path)
    for file in lfs.dir(path) do
        if file ~= "." and file ~= ".." then
            local fullpath = path..file
            print(fullpath)
            local attr = lfs.attributes (fullpath)
            assert (type(attr) == "table")
            if attr.mode == "directory" then
                fullpath = fullpath.."/"
                self:clean_dir(fullpath)
                lfs.rmdir(fullpath)
            else
                os.remove(fullpath)
            end
        end
    end
end

function UpdateScene:make_dir(path)
    if lfs.chdir(path) then
        return
    end
    local rt = string.split(path,"/")
    local tmp = ""
    for i = 1,#rt-1 do
        folder = rt[i]
        tmp = tmp..folder.."/"
        if lfs.chdir(tmp) == nil then
            lfs.mkdir(tmp)
        end
    end
end

function UpdateScene:write_file(path,content)
    self:make_dir(path)
    self:write_content_to_file(path,content)
end

function UpdateScene:lua_do_string(str)
    local fn = assert(loadstring(str));
    return fn();
end


function UpdateScene:getCurVersion()
    local curVersion = "0.1.1.1";
    return curVersion;
end
function UpdateScene:post(args)
    local cbk = args.cbk;
    local url = args.url;
    local params = args.params;
    local function httpPostCbk(event)
        local requestBack = event.request;
        if event.name ~= "completed" then
            return; 
        end
        local code = requestBack:getResponseStatusCode()
        if code ~= 200 then
            print("code ", code)
            return; 
        end
        local data = cjson.decode(requestBack:getResponseString());
        if cbk then
            cbk(data);
        end
    end;
    local request = cc.HTTPRequest:createWithUrl(httpPostCbk, url, cc.kCCHTTPRequestMethodPOST);
    --dump(params);
    for key, var in pairs(params) do
        request:addPOSTValue(var.key, var.value);
    end
    request:start();
end

function UpdateScene:getSys()
    local sys = "";
    local target = cc.Application:getInstance():getTargetPlatform()
    if target == 3 then
        sys = "a";
    elseif target == 4 or target == 5 then
        sys = "i";
    else 
        sys = "p";
    end
    return sys;
end

function UpdateScene:updateRes(res)
    local url = res.url;
    local serverVersion = res.ver;
    print(res);
    --dump(res);
end

function UpdateScene:notNeedUpdate()
    self.text:setString("当前版本为最新版本");
    local pro = cc.ProgressFromTo:create(1,0,100);
    local cbk = cc.CallFunc:create(function()
        require("config")
        require("cocos.init")
        require("framework.init")
        cc.Director:getInstance():replaceScene(require(SCRIPTS_DIR .. ".scenes.MainScene").new());
    end);
    self.progressTimer:runAction(cc.Sequence:create(pro,cbk));
end

return UpdateScene;